#coding:utf-8
import time
import sys,os
import wx
import wx.aui as aui
import customwid as wid
import wx.lib.scrolledpanel as scrolled
import wx.grid as grid
import wx.lib.buttonpanel as bp
import testcase
import stock
import ico
from buss import market

class TestTitleBar(bp.ButtonPanel):
    def __init__(self, parent, text, depend):
        bp.ButtonPanel.__init__(self, parent, -1, text)
        self.depend = depend
        btnDelete = bp.ButtonInfo(self, bmp = ico.getBmp("delete"), 
                                  shortHelp = u"删除该用例")
        self.AddButton(btnDelete)
        
        self.SetAlignment(bp.BP_ALIGN_LEFT)
        bp_art = self.GetBPArt()
        bp_art.SetMetric(bp.BP_BORDER_SIZE, 1)
        bp_art.SetColor(bp.BP_BORDER_COLOR, wx.Color(100, 54, 150))
        bp_art.SetColor(bp.BP_BACKGROUND_COLOR, wx.Color(230, 230, 222))
        bp_art.SetFont(bp.BP_TEXT_FONT, wid.Font(8))
        bp_art.SetColor(bp.BP_TEXT_COLOR, wx.Color(0, 0, 0))
        bp_art.SetMetric(bp.BP_PADDING_SIZE, wx.Size(2,0))
        self.DoLayout()
        self.Bind(wx.EVT_BUTTON, self.OnDelete, btnDelete)
        
    def OnDelete(self, evt):
        wx.CallAfter(self.GetParent().removeTestCase, self.depend)
        del self.depend
        

class DataTable(grid.Grid):
    def __init__(self, parent, bussinstance):
        grid.Grid.__init__(self, parent)
        self.bussinstance = bussinstance
        self.datalist = bussinstance.getList()
        self.CreateGrid(len(self.datalist), 1) # 创建表格
        self.SetLabelBackgroundColour(wx.WHITE)
        self.SetLabelFont(wid.Font(9))
        self.SetRowLabelSize(100)
        self.SetColLabelValue(0,'')
        self.SetColLabelSize(1)
        self.SetDefaultColSize(150)
        self.SetDefaultRowSize(20)
        self.DisableDragRowSize()
        self.makeData(self.datalist) # 输入数据
        self.Bind(grid.EVT_GRID_CELL_CHANGE, self.OnChange)
        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        
    def GetValue(self):
        data = self.bussinstance.getType() + self.bussinstance.getData()
        return data
        
    def makeData(self, datalist):
        index = 0
        for each in datalist:
            self.SetRowLabelValue(index, each[0]) # 每列名字
            self.setEditor(index, each[1]) # 设置编辑器
            value = each[2]()
            if not isinstance(value, unicode):
                value = unicode(value)
            self.SetCellValue(index, 0, value) # 设置值
            index += 1
    
    def setEditor(self, index, args):
        if isinstance(args, list):
            self.SetCellEditor(index, 0,
                        grid.GridCellChoiceEditor(args))
        elif isinstance(args, tuple):
            self.SetCellEditor(index, 0,
                        grid.GridCellNumberEditor(args[0],args[1]))
        elif isinstance(args, bool):
            self.SetCellEditor(index, 0, grid.GridCellBoolEditor())
        else:
            x = grid.GridCellAttr()
            self.SetRowAttr(index, x)
            
    def OnChange(self, evt):
        index = evt.GetRow()
        value = self.GetCellValue(index, 0)#.encode('utf-8')
        writeable = self.datalist[index][3] 
        writeable(value)
        
    def OnKeyDown(self, evt):
        if evt.GetKeyCode() != wx.WXK_RETURN:
            evt.Skip()
            return
        self.DisableCellEditControl()
        
class TestInputCtrl(wx.Window):
    def __init__(self, parent, caption, value):
        wx.Window.__init__(self, parent)
        self.SetMinSize((120, 18))
        self.caption = caption
        self.value = str(value)
        self.sep = 60
        
        editor = wx.TextCtrl(self, -1, style = wx.BORDER_SIMPLE)
        editor.SetBackgroundColour(wx.Colour(255,255,200))
        editor.SetForegroundColour(wx.Colour(0,0,0))
        editor.Hide()
        self.editor = editor
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
        self.editor.Bind(wx.EVT_KILL_FOCUS, self.CloseEditor)

    def OnPaint(self, evt):
        dc = wx.PaintDC(self)
        gc = wx.GraphicsContext.Create(dc)
        rect = self.GetClientRect()
        gc.SetBrush(wx.Brush(wx.Color(240, 240, 240)))
        gc.SetPen(wx.Pen(wx.BLACK))
        gc.DrawRectangle(self.sep , 1, rect.width-self.sep - 2, rect.height-2)
        
        gc.SetFont(wid.Font(8, bold = False) ,wx.BLACK)
        gc.DrawText(self.caption + ":  ", 1, 3)
        gc.DrawText(self.value, self.sep + 3, 3)
        evt.Skip()
        
    def OnLeftDown(self, evt):
        x, y = evt.GetPosition()
        if x < self.sep: 
            self.SetFocus()
            return
        if self.editor.IsShown(): return
        x, y = self.GetPosition()
        width, height = self.GetSize()
        editor = self.editor
        editor.SetDimensions(self.sep, 0, width- self.sep, height)
        editor.SetValue(self.value) 
        editor.Show()
        editor.Raise()
        editor.SetFocus()
        
    def CloseEditor(self, evt=None):
        if not self.editor.IsShown():
            return
        value = self.editor.GetValue()
        if value.isdigit():
            self.value = value
        self.editor.Hide()
        self.SetFocus()
        self.Refresh()
        
    def GetValue(self):
        return self.value
        
class TestCaseWindow(wid.Sizer):
    def __init__(self, parent, case =None, cls =None):
        wid.Sizer.__init__(self, wx.VERTICAL, flag = wx.EXPAND|wx.ALL, border = 2)
        self.parent = parent
        assert case or cls
        if not case:
            case = testcase.TestCase()
        
        self.repeat = TestInputCtrl(self.parent, u"连发次数", case.getRepeat())
        self.patience = TestInputCtrl(self.parent, u"忍耐时长", case.getPatience())
        self.rest = TestInputCtrl(self.parent, u"停留时长", case.getRest())
        
        if cls:
            bussinstance = cls()
        else:
            cls = market.findProtocol(case.getBussType())
            if not cls: return
            bussinstance = cls(case.getBussData())
            
        self.title = TestTitleBar(self.parent, bussinstance.name, self)
        self.data = DataTable(self.parent, bussinstance)
        
        sizer = wid.Sizer(wx.HORIZONTAL, flag = wx.ALL, border = 1)
        sizer.Attach( self.repeat, self.patience, self.rest)
        self.Attach(self.title, sizer, self.data)
        self.Layout()
    
    def getTestCase(self):
        case = testcase.TestCase(self.data.GetValue(), self.repeat.GetValue(),
                                 self.patience.GetValue(), self.rest.GetValue())
        return case

class TestFlowPanel(scrolled.ScrolledPanel):
    def __init__(self, parent):
        scrolled.ScrolledPanel.__init__(self, parent)
        self.SetBackgroundColour(wx.WHITE)
        self.testList = []
        self.mainsizer = wid.Sizer(wx.VERTICAL, flag = wx.EXPAND|wx.ALL, border = 5)
        self.SetSizer(self.mainsizer)
        self.SetupScrolling()
        
    def newTestCase(self, bussClass):
        self.Freeze()
        case = TestCaseWindow(self, cls = bussClass)
        self.testList.append(case)
        self.mainsizer.Add(case)
        self.Thaw()
        self.SetupScrolling()
    
    def removeTestCase(self, case):
        self.testList.remove(case)
        case.Clear(True)
        self.mainsizer.Remove(case)
        self.SetupScrolling()
        
    def clearTestCase(self):
        self.Freeze()
        for i in xrange(len(self.testList)):
            case = self.testList.pop(0)
            case.Clear(True)
            self.mainsizer.Remove(case)
        self.Thaw()
        self.SetupScrolling()
    
    def exportTest(self):
        testFlow = testcase.TestFlow()
        for case in self.testList:
            testFlow.appendTestCase(case.getTestCase())
        return testFlow
        
    def importTest(self, testFlow):
        self.Freeze()
        for testCase in testFlow.getTestList():
            case = TestCaseWindow(self, case = testCase)
            self.mainsizer.Add(case)
            self.testList.append(case)
        self.Thaw()
        self.SetupScrolling()
    

class FunctionPanel(wx.TreeCtrl):
    def __init__(self,parent):
        wx.TreeCtrl.__init__(self, parent ,style = wx.TR_HIDE_ROOT)
        self.root = self.AddRoot('root')
        for operations in market.operations:
            mitem = self.AppendItem(self.root, operations[0])
            for operation in operations[1]:
                item = self.AppendItem(mitem, operation.name)
                self.SetItemPyData(item, operation)
            self.Expand(mitem)
        self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemSelect)
        
    def OnItemSelect(self, evt):
        item = evt.GetItem()
        operation = self.GetItemPyData(item)
        if operation is not None: 
            self.GetParent().newTestCase(operation)

class SaveDialog(wx.Dialog):
    def __init__(self, parent, path):
        wx.Dialog.__init__(self, parent, size=(300, 250), title = u"是否保存数据", 
                              style=wx.DEFAULT_DIALOG_STYLE |wx.FRAME_FLOAT_ON_PARENT)
        self.path = path
        test_flow = self.GetParent().testFlows.exportTest()
        panel = wx.Panel(self)
        labelName = wx.StaticText(panel, label = u"名称:")
        self.name = wx.TextCtrl(panel, value = test_flow.getName(), size = (200, 18))
        labelDescription = wx.StaticText(panel, label = u"说明:")
        self.description = wx.TextCtrl(panel, value = test_flow.getDescription(),
                                       size = (280, 100), style=wx.TE_MULTILINE)
        btnOK = wx.Button(panel, label = u"确定")
        btnCancel = wx.Button(panel, label = u"取消")
        
        sizer = wid.Sizer(wx.HORIZONTAL, flag = wx.ALL, border = 2)
        sizer.Attach(btnOK, btnCancel)
        mainsizer = wid.Sizer(wx.VERTICAL, flag = wx.ALL, border = 5)
        mainsizer.Attach(labelName, self.name, labelDescription, self.description,
                         sizer)
        panel.SetSizer(mainsizer)
        panel.Fit()
        
        self.Bind(wx.EVT_BUTTON, self.OnButtonOK, btnOK)
        self.Bind(wx.EVT_BUTTON, self.OnButtonCancel, btnCancel)
        
    def OnButtonOK(self, evt):
        test_flow = self.GetParent().testFlows.exportTest()
        test_flow.setName(self.name.GetValue())
        test_flow.setDescription(self.description.GetValue())
        self.EndModal(wx.ID_OK)
        
    def OnButtonCancel(self, evt):
        self.EndModal(wx.ID_CANCEL)
        
        
class ExportDialog(wx.Dialog):
    def __init__(self, parent):
        wx.Dialog.__init__(self, parent, size=(300, 250), title = u"导出数据", 
                              style=wx.DEFAULT_DIALOG_STYLE |wx.FRAME_FLOAT_ON_PARENT)
        test_flow = self.GetParent().testFlows.exportTest()
        panel = wx.Panel(self)
        labelName = wx.StaticText(panel, label = u"名称:")
        self.name = wx.TextCtrl(panel, value = test_flow.getName(), size = (200, 18))
        labelDescription = wx.StaticText(panel, label = u"说明:")
        self.description = wx.TextCtrl(panel, value = test_flow.getDescription(),
                                       size = (280, 100), style=wx.TE_MULTILINE)
        btnOK = wx.Button(panel, label = u"确定")
        btnCancel = wx.Button(panel, label = u"取消")
        
        sizer = wid.Sizer(wx.HORIZONTAL, flag = wx.ALL, border = 2)
        sizer.Attach(btnOK, btnCancel)
        mainsizer = wid.Sizer(wx.VERTICAL, flag = wx.ALL, border = 5)
        mainsizer.Attach(labelName, self.name, labelDescription, self.description,
                         sizer)
        panel.SetSizer(mainsizer)
        panel.Fit()
        
        self.Bind(wx.EVT_BUTTON, self.OnButtonOK, btnOK)
        self.Bind(wx.EVT_BUTTON, self.OnButtonCancel, btnCancel)
        
    def OnButtonOK(self, evt):
        test_flow = self.GetParent().testFlows.exportTest()
        test_flow.setName(self.name.GetValue())
        test_flow.setDescription(self.description.GetValue())
        self.EndModal(wx.ID_OK)
        
    def OnButtonCancel(self, evt):
        self.EndModal(wx.ID_CANCEL)
        


class MainForm(wx.Frame):
    titleName = u"用例编辑器 test editor - "
    NEWFILENAME = u"new script"
    def __init__(self, *args, **kw):
        wx.Frame.__init__(self, *args, **kw)
        self.fileName = self.NEWFILENAME
        self._initLayout()
        self.refreshTitle()
            
    def _initLayout(self):
        self.operation = wid.OperationPanel(self, "")
        items = (
                 (ico.getBmp("filenew"), wx.ITEM_NORMAL, u"新建脚本", self.OnFileNew),
                 (ico.getBmp("fileopen"), wx.ITEM_NORMAL, u"打开脚本", self.OnFileOpen),
                 (ico.getBmp("filesave"), wx.ITEM_NORMAL, u"保存", self.OnFileSave), 
                 (ico.getBmp("filesaveas"), wx.ITEM_NORMAL, u"另存为", self.OnFileSaveAs), 
                 (ico.getBmp("fileexport"), wx.ITEM_NORMAL, u"导出", self.OnExport),
                 )
        self.operation.layout(items)
        self.testFlow = TestFlowPanel(self)
        self.function = FunctionPanel(self)
        self.status = self.CreateStatusBar()
        
        self.mgr=aui.AuiManager()
        self.mgr.SetManagedWindow(self)
        self.mgr.AddPane(self.operation, aui.AuiPaneInfo().Name("operation").
                                  Caption(u"操作栏").Top().Floatable(False).
                                  MinSize((200, -1)).ToolbarPane())
                             
        self.mgr.AddPane(self.testFlow,aui.AuiPaneInfo().Name("testcase").
                                  Caption(u"用例设计").Center().
                                  CloseButton(False).MaximizeButton(True))
        
        self.mgr.AddPane(self.function, aui.AuiPaneInfo().Name("function").BestSize((150,-1)).
                                  Caption(u"功能列表").Left().Floatable(False).
                                  CloseButton(False).MaximizeButton(True))
                                
        self.mgr.Update()
        #self.Bind(wx.EVT_CLOSE, self.OnClose)
        #self.Bind(wx.EVT_SIZE, self.OnSize)

    def OnFileNew(self, evt):
        evt.GetEventObject().SetFocus()
        self.askForSaving()
        self.testFlow.clearTestCase()
        self.fileName = self.NEWFILENAME
        self.refreshTitle()
        
    def OnFileOpen(self, evt):
        evt.GetEventObject().SetFocus()
        self.askForSaving()
        self.testFlow.clearTestCase()
        dlg = wid.TestCaseOpenDialog(self)
        if dlg.ShowModal() == wx.ID_OK:
            paths = dlg.GetPaths()
            for path in paths:
                self.importTest(path)
        dlg.Destroy()
        
    def OnFileSave(self, evt):
        evt.GetEventObject().SetFocus()
        self.savetestFlow()
        self.refreshTitle()
        
    def OnFileSaveAs(self, evt):
        evt.GetEventObject().SetFocus()
        self.savetestFlow(True)
        self.refreshTitle()
        
    def OnExport(self, evt):
        evt.GetEventObject().SetFocus()
        if self.GetParent() is None:
            dlg = wid.WarningDialog(self, u"无法导出到相应目标")
            dlg.ShowModal()
            dlg.Destroy()
        else:
            self.savetestFlow()
            if self.fileName != self.NEWFILENAME:
                self.GetParent().importTest(self.fileName)
                self.Destroy()

    def savetestFlow(self, changed = False):
        testFlow = self.testFlow.exportTest()
        if not testFlow:
            dlg = wid.WarningDialog(self, u"空的测试用例,未执行存储.")
            dlg.ShowModal()
            dlg.Destroy()
            return
        if self.fileName != self.NEWFILENAME and not changed:
            path = self.fileName
        else:
            dlg = wid.TestCaseSaveDialog(self)
            if dlg.ShowModal() == wx.ID_OK:
                path = dlg.GetPaths()[0]
                dlg.Destroy()
            else:
                path = ""
        if path:
            testFlow.setName(os.path.basename(path).rstrip('.test'))
            stock.dump(testFlow, path)
            if not changed:
                self.fileName = path
            return testFlow
    
    def askForSaving(self):
        testFlow = self.testFlow.exportTest()
        if testFlow.getCount() == 0: return
        dlg = wid.AskingDialog(self, u"是否存储现在的脚本文件?")
        if dlg.ShowModal() == wx.ID_OK:
            self.savetestFlow()
        dlg.Destroy()
        
    def refreshTitle(self):
        self.SetTitle("%s%s"%(self.titleName, self.fileName))

    def newTestCase(self, *args, **kw):
        self.testFlow.newTestCase(*args, **kw)
        
    def importTest(self, filename):
        self.testFlow.importTest(stock.load(filename))
        self.fileName = filename
        self.refreshTitle()
        
if __name__ == '__main__':
    app = wx.App(0)
    f = MainForm(None, size=(700,400))
    f.Show()
    app.MainLoop()